using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace AutoBackup
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string log = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\logs\\01AutoBackupLogs.txt";

            // 要备份的目录列表
            // <给目录起个名称，所在路径>
            Dictionary<string, string> sources = new Dictionary<string, string>
            {
                { "01tiddlywiki", @"D:\A_DataBases\tiddlywiki\*" },
                { "02blog", @"D:\A_DataBases\blog\*" },
                { "03keepass", @"D:\A_DataBases\keepass\*" },
                { "04WorkSpace", @"D:\A_DataBases\WorkSpace\*" },
                { "05Pictures", @"C:\Users\Administrator\Pictures\*" },
                { "06source", @"C:\Users\Administrator\source\*" },
                { "07wechatFile", @"C:\Users\Administrator\Documents\WeChat Files\wxid_fmin7lmfk7qj21\FileStorage\File\*" },
                { "08qqFile", @"C:\Users\Administrator\Documents\Tencent Files\599526745\FileRecv\*" }
            };

            //要保存到哪个目录？
            string backupDir = @"D:\Backup\";

            //目录拼接
            string now = System.DateTime.Now.ToString("yyyy-MM-dd");
            var backupFiles = new List<BackupModel>();
            //int index = 1;
            foreach (var source in sources)
            {
                // D:\Backup\sourceName\sourceName-now.7z
                StringBuilder sb = new StringBuilder();
                sb.Append(backupDir);
                //sb.Append(index++.ToString("00"));
                sb.Append(source.Key);
                sb.Append("\\");
                sb.Append(source.Key);
                sb.Append("-");
                sb.Append(now);
                sb.Append(".7z");
                var backup = new BackupModel()
                {
                    SourceDir = source.Value,
                    TargetDir = sb.ToString(),
                    TargetName = source.Key,
                };
                backupFiles.Add(backup);
            }

            //md5加密，在执行程序的时候，传入密码参数
            string passwd = MD5Encrypt.MD5Encrypt64(args[0]);

            //生成7z命令
            List<string> cmds = new List<string>();
            foreach (var file in backupFiles)
            {
                var cmd = new StringBuilder();
                cmd.Append("\"C:\\Program Files\\7-Zip\\7z.exe\" ");
                cmd.Append("a ");
                cmd.Append("-t7z ");//压缩格式
                cmd.Append(file.TargetDir);
                cmd.Append(" ");
                cmd.Append(file.SourceDir);
                cmd.Append(" ");

                //如果是工作目录，就不压缩了，只打包就行
                if (file.TargetName == "04WorkSpace")
                {
                    cmd.Append("-mx=0 ");//压缩等级
                }
                else
                {
                    cmd.Append("-mx=5 ");//压缩等级
                }

                cmd.Append($"-p{passwd}");//设置密码
                //cmd.Append("-mhe");//加密文件头
                cmds.Add(cmd.ToString());

                if (!Directory.Exists(Path.GetDirectoryName(file.TargetDir)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(file.TargetDir));
                }

                ////删除5天前的文件
                DeleteOldFiles(Path.GetDirectoryName(file.TargetDir), 5);
            }

            //执行cmd命令
            RunCmd(cmds);

            //生成日志文件
            if (!Directory.Exists(Path.GetDirectoryName(log)))
                Directory.CreateDirectory(Path.GetDirectoryName(log));

            if (!File.Exists(log))
                File.Create(log).Close();
            using (var sw = File.AppendText(log))
            {
                sw.WriteLine("Autobackup " + DateTime.Now.ToString("F"));
                sw.Close();
            }

        }

        public static void DeleteOldFiles(string dir, int days)
        {
            try
            {
                if (!Directory.Exists(dir) || days < 1) return;

                var now = DateTime.Now;
                foreach (var f in Directory.GetFileSystemEntries(dir).Where(f => File.Exists(f)))
                {
                    var t = File.GetCreationTime(f);

                    var elapsedTicks = now.Ticks - t.Ticks;
                    var elapsedSpan = new TimeSpan(elapsedTicks);

                    if (elapsedSpan.TotalDays > days) File.Delete(f);
                }
            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// 执行多条命令
        /// </summary>
        /// <param name="cmds"></param>
        /// <returns></returns>
        public static string RunCmd(List<string> cmds)
        {
            //string strInput = Console.ReadLine();
            using (var p = new Process())
            {
                p.StartInfo.FileName = "cmd.exe";  //设置要启动的应用程序
                p.StartInfo.UseShellExecute = false;//是否使用操作系统shell启动
                p.StartInfo.RedirectStandardInput = true; // 接受来自调用程序的输入信息
                p.StartInfo.RedirectStandardOutput = true;//输出信息
                p.StartInfo.RedirectStandardError = true; // 输出错误
                p.StartInfo.CreateNoWindow = true;  //不显示程序窗口
                p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

                p.Start(); //启动程序

                foreach (var cmd in cmds)
                {
                    p.StandardInput.WriteLine(cmd);//向cmd窗口发送输入信息
                }

                p.StandardInput.WriteLine("exit"); // 执行完成之后退出窗口
                p.StandardInput.AutoFlush = true;
                string strOuput = p.StandardOutput.ReadToEnd(); //获取输出信息
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
                return strOuput;
            }
        }
    }

    public class BackupModel
    {
        public string TargetName { get; set; }
        public string TargetDir { get; set; }
        public string SourceDir { get; set; }
    }

    public class MD5Encrypt
    {
        public static string MD5Encrypt32(string password)
        {
            string cl = password;
            string pwd = "";
            MD5 md5 = MD5.Create();
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
            for (int i = 0; i < s.Length; i++)
            {
                pwd = pwd + s[i].ToString("X");
            }
            return pwd;
        }

        public static string MD5Encrypt64(string password)
        {
            string cl = password;
            MD5 md5 = MD5.Create(); //实例化一个md5对像
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
            return Convert.ToBase64String(s);
        }
    }
}